import random
from db import DB


class Unit():
    """
    单位类
    params: 
        name: [str] 单位名称
        level: [int] 等级
        exp: [int] 经验值
        max_exp: [int] 最大经验值
        hp: [int]血量
        atk: [int] 攻击力
        defense: [int] 防御力
        hit: [float] 命中率
        dod: [float] 闪避率
        cri: [float] 暴击率
        level_exp: [int] 升级增加经验值
        level_hp: [int] 升级增加最大血量
        level_atk: [int] 升级增加攻击力
        level_defense: [int] 升级增加防御力
        level_hit: [float] 升级增加命中率
        level_dod: [float] 升级增加闪避率
        level_cri: [float] 升级增加暴击率
        skill: [str] 技能列表 -> 技能编号列表
        equipment: [str] 装备列表 -> 装备编号列表

    func:
        attack: 攻击
        be_attacked: 被攻击
        get_exp： 获得经验值
        use_item： 使用/卸下 道具
    """

    def __init__(self, name="", level=1, exp=0, max_exp=0, hp=0, atk=0, defense=0, hit=0, dod=0, cri=0, level_exp=0, level_hp=0, level_atk=0, level_defense=0, level_hit=0, level_dod=0, level_cri=0, skill="", equipment=""):
        self.name = name
        self.level = int(level)
        self.exp = int(exp)
        self.max_exp = int(max_exp)
        self.hp = int(hp)
        self.atk = int(atk)
        self.defense = int(defense)
        self.hit = float(hit)
        self.dod = float(dod)
        self.cri = float(cri)
        self.level_exp = int(level_exp)
        self.level_hp = int(level_hp)
        self.level_atk = int(level_atk)
        self.level_defense = int(level_defense)
        self.level_hit = float(level_hit)
        self.level_dod = float(level_dod)
        self.level_cri = float(level_cri)
        self.skill = DB().get_skill(skill)
        self.equipment = DB().get_item_all(equipment) if equipment else []

    def r(self):
        unit_attr = {
            "name": self.name,
            "level": self.level,
            "exp": self.exp,
            "max_exp": self.max_exp,
            "hp": self.hp,
            "atk": self.atk,
            "defense": self.defense,
            "hit": self.hit,
            "dod": self.dod,
            "cri": self.cri,
            "level_exp": self.level_exp,
            "level_hp": self.level_hp,
            "level_atk": self.level_atk,
            "level_defense": self.level_defense,
            "level_hit": self.level_hit,
            "level_dod": self.level_dod,
            "skill": self.skill,
            "equipment": self.equipment,
        }

        return unit_attr

    def attack(self):
        """
        攻击
        return: [tuple] 攻击属性：技能名称 攻击力 命中率 是否暴击
        """
        skill = self.__release_skill()

        is_cri = self.__be_cri(skill["cri"])

        name = skill["name"]
        atk = skill["atk"] + self.atk * (2 if is_cri else 1)
        hit = round((skill["hit"] + self.hit) / 2, 2)

        return (name, atk, hit, is_cri)

    def Mattack(self):
        """
        怪物攻击
        return: [tuple] 攻击属性：技能名称 攻击力 命中率 是否暴击
        """
        is_cri = self.__be_cri()
        atk = self.atk * (2 if is_cri else 1)

        return (atk, self.hit, is_cri)

    def be_attacked(self, atk, hit):
        """
        被攻击
        params:
            atk: [int] 攻击力
            hit: [float] 命中率
        return: [tuple] 被攻击： [bool]是否命中 [int]受到的伤害 [bool]是否死亡
        """

        if not self.__be_hit(hit):
            return (False, 0, False)

        return (True, self.__injure(atk), self.__is_dead())

    def get_exp(self, exp, level=0, skill=[]):
        """
        获得经验值
        params: 
            exp: [int] 获得经验值

        return: [tuple] -> [bool] 是否提升等级
                           [int] 学会技能的id
        """
        self.exp += exp
        exp = 0

        # 升级
        if self.exp >= self.max_exp:
            self.exp -= self.max_exp
            new_skill = self.__level_up()
            if new_skill:
                skill.append(new_skill)
            level += 1
            self.get_exp(exp, level, skill)
        return (level, skill)

    def use_item(self, attr, type=1):
        """
        使用/卸下道具
        params:
            attr: [tuple] 属性变化数据
            type: 1使用 -1卸下
        return: 提升等级
                学会技能
        """
        
        skill = self.__level_up(type * attr["level"])
        levelup = self.get_exp(type * attr["exp"])
        self.__cal_hp(type * attr["hp"])
        self.__cal_atk(type * attr["atk"])
        self.__cal_defense(type * attr["defense"])
        self.__cal_hit(type * attr["hit"])
        self.__cal_dod(type * attr["dod"])
        self.__cal_cri(type * attr["cri"])

        return (attr["level"] if attr["level"] >= levelup[0] else levelup, skill)

    def __cal_max_exp(self, num):
        """
        最大经验值变化
        """
        self.max_exp += num

    def __cal_hp(self, num):
        self.hp += num

    def __cal_atk(self, num):
        """
        攻击力变化
        """
        self.atk += num

    def __cal_defense(self, num):
        """
        防御力变化
        """
        self.defense += num

    def __cal_hit(self, num):
        """
        命中率变化
        """
        self.hit = round(self.hit + num, 2)

        if self.hit >= 100:
            self.hit = 100
            return False
        return True

    def __cal_dod(self, num):
        """
        闪避率变化
        """
        self.dod = round(self.dod + num, 2)

        if self.dod >= 100:
            self.dod = 100
            return False
        return True

    def __cal_cri(self, num):
        """
        暴击率变化
        """
        self.cri = round(self.cri + num, 2)

        if self.cri >= 100:
            self.cri = 100
            return False
        return True

    def __is_dead(self):
        if self.hp <= 0:
            return True
        return False

    def __level_up(self, level=1):
        """
        升级
        return: 学会的技能id
        """
        if level > 0:
            self.level += level
            self.__cal_max_exp(self.level_exp * level)
            self.hp += self.level_hp * level
            self.__cal_atk(self.level_atk * level)
            self.__cal_defense(self.level_defense * level)
            self.__cal_hit(self.level_hit * level)
            self.__cal_dod(self.level_dod * level)
            self.__cal_cri(self.level_cri * level)

            if self.level in (3, 5, 8, 10, 12, 15, 18, 20, 25):
                if self.level == 3:
                    skill = 2
                elif self.level == 5:
                    skill = 3
                elif self.level == 8:
                    skill = 4
                elif self.level == 10:
                    skill = 5
                elif self.level == 12:
                    skill = 6
                elif self.level == 15:
                    skill = 7
                elif self.level == 18:
                    skill = 8
                elif self.level == 20:
                    skill = 9
                elif self.level == 25:
                    skill = 10
                
                self.skill.append(DB().get_skill(str(skill))[0])
            else:
                skill = False

            return skill
        return False

    def __release_skill(self):
        """
        选择技能
        return: [obj] 技能属性
        """
        if self.skill:
            skill_use_rate_list = []

            for skill in self.skill:
                skill_use_rate_list += [skill["id"]] * int(skill["rate"] * 100)

            release_skill_id = self.__cal_choose(skill_use_rate_list)

            for skill in self.skill:
                if skill["id"] == release_skill_id:
                    return skill

    def __be_hit(self, hit):
        """
        判断是否命中
        """
        hit_rate_list = [1] * int(hit * 100) + [0] * int(self.dod * 50)
        hit = hit_rate_list[self.__cal_choose(hit_rate_list)]

        if hit == 1:
            return True
        return False

    def __be_cri(self, skill_cri=0):
        if skill_cri != 0:
            cri = (self.cri + skill_cri) / 2
        else:
            cri = self.cri
        cri_rate_list = [1] * int(cri * 100) + [0] * int((100 - cri) * 100)
        cri = cri_rate_list[self.__cal_choose(cri_rate_list)]
        if cri == 1:
            return True
        return False

    def __injure(self, hit):
        """
        受伤害
        """
        injure = hit - (self.defense // 2)
        injure = 0 if injure < 0 else injure
        self.hp -= injure
        return injure

    @staticmethod
    def __cal_choose(obj):
        """
        根据概率列表随机返回
        """
        random.shuffle(obj)
        return obj[random.randint(0, len(obj) - 1)]


if __name__ == "__main__":
    hero = Unit("勇者", 1, 0, 100, 200, 10, 5, 200, 5, 10, 100, 500, 10, 5, 1, 1, 1, [1, 2])
